// OpenGL Extensions
// (c) jimon game studio

#ifndef JEH_CRENDER_OPENGL_EXTENSIONS
#define JEH_CRENDER_OPENGL_EXTENSIONS

#include "jeTypes.h"
#include "jeUnknown.h"
#include "jeOpenGLSystemHeader.h"

#ifdef JE_RENDER_OPENGL

#include "jeOpenGLWorkMode.h"

//#define JE_OPENGL_MANIACAL_DEBUG
//#define JE_DYNAMIC_LINKAGE_CORE_FUNCTIONAL

#ifndef JE_DYNAMIC_LINKAGE_CORE_FUNCTIONAL
#include <GL/gl.h>
#endif

#ifdef JE_OPENGL_MANIACAL_DEBUG
#include "ILogManager.h"
#endif

namespace je
{
	namespace video
	{
		//! OpenGL Extensions Class
		class CRender_OpenGL_Extensions:public je::jeUnknown
		{
		protected:
			//Core Functional
			#ifdef JE_DYNAMIC_LINKAGE_CORE_FUNCTIONAL
			PFNGLCULLFACEPROC glCullFace;
			PFNGLTEXPARAMETERIPROC glTexParameteri;
			PFNGLTEXIMAGE2DPROC glTexImage2D;
			PFNGLCLEARPROC glClear;
			PFNGLCLEARCOLORPROC glClearColor;
			PFNGLCLEARDEPTHPROC glClearDepth;
			PFNGLDEPTHMASKPROC glDepthMask;
			PFNGLDISABLEPROC glDisable;
			PFNGLENABLEPROC glEnable;
			PFNGLFLUSHPROC glFlush;
			PFNGLBLENDFUNCPROC glBlendFunc;
			PFNGLDEPTHFUNCPROC glDepthFunc;
			PFNGLGETERRORPROC glGetError;
			PFNGLGETSTRINGPROC glGetString;
			PFNGLVIEWPORTPROC glViewport;
			PFNGLDRAWELEMENTSPROC glDrawElements;
			PFNGLCOPYTEXIMAGE2DPROC glCopyTexImage2D;
			PFNGLBINDTEXTUREPROC glBindTexture;
			PFNGLDELETETEXTURESPROC glDeleteTextures;
			PFNGLGENTEXTURESPROC glGenTextures;
			PFNGLDRAWBUFFERPROC glDrawBuffer;
			PFNGLREADBUFFERPROC glReadBuffer;
			#endif
				
			//VSync Extension
			#ifdef JE_WIN
			PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
			#endif
			#ifdef JE_LINUX
			#endif

			//Hardware Buffers
			PFNGLGENBUFFERSPROC glGenBuffers;
			PFNGLBINDBUFFERPROC glBindBuffer;
			PFNGLBUFFERDATAPROC glBufferData;
			PFNGLDELETEBUFFERSPROC glDeleteBuffers;
			PFNGLMAPBUFFERPROC glMapBuffer;
			PFNGLUNMAPBUFFERPROC glUnmapBuffer;

			//Draw Range Elements
			PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements;

			//MultiTexturing
			PFNGLACTIVETEXTUREPROC glActiveTexture;

			//AA Textures
			PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;

			//FBO
			PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
			PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
			PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
			PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
			PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
			PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
			PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
			PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
			PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
			PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
			PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
			PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
			PFNGLDRAWBUFFERSPROC glDrawBuffers;
			PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
			PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;

			//GLSL
			PFNGLATTACHSHADERPROC glAttachShader;
			PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
			PFNGLCOMPILESHADERPROC glCompileShader;
			PFNGLCREATEPROGRAMPROC glCreateProgram;
			PFNGLCREATESHADERPROC glCreateShader;
			PFNGLDELETEPROGRAMPROC glDeleteProgram;
			PFNGLDELETESHADERPROC glDeleteShader;
			PFNGLDETACHSHADERPROC glDetachShader;
			PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
			PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
			PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
			PFNGLGETPROGRAMIVPROC glGetProgramiv;
			PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
			PFNGLGETSHADERIVPROC glGetShaderiv;
			PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
			PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
			PFNGLLINKPROGRAMPROC glLinkProgram;
			PFNGLSHADERSOURCEPROC glShaderSource;
			PFNGLUSEPROGRAMPROC glUseProgram;
			PFNGLUNIFORM2FPROC glUniform2f;
			PFNGLUNIFORM3FPROC glUniform3f;
			PFNGLUNIFORM2IPROC glUniform2i;
			PFNGLUNIFORM3IPROC glUniform3i;
			PFNGLUNIFORM1FVPROC glUniform1fv;
			PFNGLUNIFORM3FVPROC glUniform3fv;
			PFNGLUNIFORM1IVPROC glUniform1iv;
			PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv;
			PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
			PFNGLVALIDATEPROGRAMPROC glValidateProgram;
			PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
			PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation;

			//! Set Null Pointers
			void SetNullPointers();

			//! Get Pointers
			void GetPointers();

			//! OpenGL Work Mode
			OpenGLWorkMode CurrentWorkMode;

		public:
			//! Constructor
			CRender_OpenGL_Extensions(OpenGLWorkMode WorkMode);

			//! Destructor
			~CRender_OpenGL_Extensions();

			//! Update Extensions
			void UpdateExtensions()
			{
				SetNullPointers();
				GetPointers();
			}

			#ifdef JE_OPENGL_MANIACAL_DEBUG
				jeStringc CheckTempError()
				{
					s32 GLError = glGetError();
					jeStringc Error;
					if(GLError)
					{
						switch(GLError)
						{
						case GL_INVALID_ENUM:
							Error = "Invalid enum";
							break;
						case GL_INVALID_VALUE:
							Error = "Invalid value";
							break;
						case GL_INVALID_OPERATION:
							Error = "Invalid operation";
							break;
						case GL_OUT_OF_MEMORY:
							Error = "Out of memory";
							break;
						default:
							Error = "Unknown error";
							break;
						}
					}
					return Error;
				}
				#define JE_CHECK_OPENGL_ERROR {jeStringc Error = CheckTempError();\
											if(Error.size()>0) JELOG_E(jeStringc("OpenGL Error : ")+Error)}
				#define JE_CHECK_NO_EXT else{JELOG_E("NO EXT")
			#else
				#define JE_CHECK_NO_EXT {
				#define JE_CHECK_OPENGL_ERROR
			#endif

			#define JE_RENDER_OPENGL_EXTENSIONS_SAFEMODE

			#ifdef JE_RENDER_OPENGL_EXTENSIONS_SAFEMODE
				#define JE_OPENGL_EXT(__Name,__Args) if(__Name) __Name __Args;\
													JE_CHECK_NO_EXT}\
													JE_CHECK_OPENGL_ERROR
				#define JE_OPENGL_EXT_RET(__Name,__Args,__Type) if(__Name){\
												__Type Var = __Name __Args;\
												JE_CHECK_OPENGL_ERROR\
												return Var;}
				#define JE_OPENGL_EXT_RET_ELSE(__Return) JE_CHECK_NO_EXT\
														return __Return;}\
														
			#else
				#define JE_OPENGL_EXT(__Name,__Args) __Name __Args;\
													JE_CHECK_OPENGL_ERROR
				#define JE_OPENGL_EXT_RET(__Name,__Args,__Type) __Type Var = __Name __Args;\
															JE_CHECK_OPENGL_ERROR\
															return Var;
				#define JE_OPENGL_EXT_RET_ELSE(__Return)
			#endif

			#define JE_OPENGL_CORE(__Name,__Args) __Name __Args;\
												JE_CHECK_OPENGL_ERROR
			#define JE_OPENGL_CORE_RET(__Name,__Args,__Type) __Type Var = __Name __Args;\
														JE_CHECK_OPENGL_ERROR\
														return Var;
			#define JE_OPENGL_CORE_RET_ELSE(__Return) 

			#define JE_OPENGL_INLINE inline

			//! Cull Face Mode
			JE_OPENGL_INLINE void CullFace(GLenum Mode)
			{
				JE_OPENGL_CORE(glCullFace,(Mode))
			}

			//! Texture Parameter
			JE_OPENGL_INLINE void TextureParameter(GLenum Target,GLenum ParamName,GLint Param)
			{
				JE_OPENGL_CORE(glTexParameteri,(Target,ParamName,Param))
			}

			//! Load Texture 2D
			JE_OPENGL_INLINE void LoadTexture2D(GLenum Target,GLint Level,GLint InternalFormat,GLsizei Width,GLsizei Height,GLint Border,GLenum Format,GLenum Type,const GLvoid * Pixels)
			{
				JE_OPENGL_CORE(glTexImage2D,(Target,Level,InternalFormat,Width,Height,Border,Format,Type,Pixels))
			}

			//! Clear Viewport
			JE_OPENGL_INLINE void ClearViewport(GLbitfield Mask)
			{
				JE_OPENGL_CORE(glClear,(Mask))
			}

			//! Set Clear Color
			JE_OPENGL_INLINE void SetClearColor(GLclampf Red,GLclampf Green,GLclampf Blue,GLclampf Alpha)
			{
				JE_OPENGL_CORE(glClearColor,(Red,Green,Blue,Alpha))
			}

			//! Set Clear Depth
			JE_OPENGL_INLINE void SetClearDepth(GLclampd Depth)
			{
				JE_OPENGL_CORE(glClearDepth,(Depth))
			}

			//! Set Depth Mask
			JE_OPENGL_INLINE void SetDepthMask(GLboolean Flag)
			{
				JE_OPENGL_CORE(glDepthMask,(Flag))
			}

			//! Disable
			JE_OPENGL_INLINE void Disable(GLenum Cap)
			{
				JE_OPENGL_CORE(glDisable,(Cap))
			}

			//! Enable
			JE_OPENGL_INLINE void Enable(GLenum Cap)
			{
				JE_OPENGL_CORE(glEnable,(Cap))
			}

			//! Flush
			JE_OPENGL_INLINE void Flush()
			{
				JE_OPENGL_CORE(glFlush,())
			}

			//! Set Blend Function
			JE_OPENGL_INLINE void SetBlendFunction(GLenum SFactor,GLenum DFactor)
			{
				JE_OPENGL_CORE(glBlendFunc,(SFactor,DFactor))
			}

			//! Set Depth Function
			JE_OPENGL_INLINE void SetDepthFunction(GLenum Function)
			{
				JE_OPENGL_CORE(glDepthFunc,(Function))
			}

			//! Get Error
			JE_OPENGL_INLINE GLenum GetError()
			{
				JE_OPENGL_CORE_RET(glGetError,(),GLenum)
				JE_OPENGL_CORE_RET_ELSE(0)
			}

			//! Get String
			JE_OPENGL_INLINE const GLubyte * GetString(GLenum Name)
			{
				JE_OPENGL_CORE_RET(glGetString,(Name),const GLubyte *)
				JE_OPENGL_CORE_RET_ELSE("No glGetString")
			}

			//! Set Viewport
			JE_OPENGL_INLINE void SetViewport(GLint X,GLint Y,GLsizei Width,GLsizei Height)
			{
				JE_OPENGL_CORE(glViewport,(X,Y,Width,Height))
			}

			//! Draw Elements
			JE_OPENGL_INLINE void DrawElements(GLenum Mode,GLsizei Count,GLenum Type,const GLvoid * Indices)
			{
				JE_OPENGL_CORE(glDrawElements,(Mode,Count,Type,Indices))
			}

			//! Copy Texture Image 2D
			JE_OPENGL_INLINE void CopyTextureImage2D(GLenum Target,GLint Level,GLenum InternalFormat,GLint X,GLint Y,GLsizei Width,GLsizei Height,GLint Border)
			{
				JE_OPENGL_CORE(glCopyTexImage2D,(Target,Level,InternalFormat,X,Y,Width,Height,Border))
			}

			//! Bind Texture
			JE_OPENGL_INLINE void BindTexture(GLenum Target,GLuint Texture)
			{
				JE_OPENGL_CORE(glBindTexture,(Target,Texture))
			}

			//! Delete Textures
			JE_OPENGL_INLINE void DeleteTextures(GLsizei Count,const GLuint * Textures)
			{
				JE_OPENGL_CORE(glDeleteTextures,(Count,Textures))
			}

			//! Create Textures
			JE_OPENGL_INLINE void CreateTextures(GLsizei Count,GLuint * Textures)
			{
				JE_OPENGL_CORE(glGenTextures,(Count,Textures))
			}

			//! Set Draw Buffer
			JE_OPENGL_INLINE void SetDrawBuffer(GLenum Mode)
			{
				JE_OPENGL_CORE(glDrawBuffer,(Mode))
			}

			//! Set Read Buffer
			JE_OPENGL_INLINE void SetReadBuffer(GLenum Mode)
			{
				JE_OPENGL_CORE(glReadBuffer,(Mode))
			}

			//! Enable VSync
			JE_OPENGL_INLINE void EnableVSync(u1 Enable)
			{
				#ifdef JE_WIN
				JE_OPENGL_EXT(wglSwapIntervalEXT,(Enable))
				#endif

				#ifdef JE_LINUX
				#endif
			}

			//! Generate Buffer
			JE_OPENGL_INLINE void GenerateBuffer(GLsizei Size,GLuint * PointerToId)
			{
				JE_OPENGL_EXT(glGenBuffers,(Size,PointerToId))
			}

			//! Bind Buffer
			JE_OPENGL_INLINE void BindBuffer(GLenum Target,GLuint Id)
			{
				JE_OPENGL_EXT(glBindBuffer,(Target,Id))
			}

			//! Set Buffer Data
			JE_OPENGL_INLINE void BufferData(GLenum target, GLsizei size, const void * data, GLenum usage)
			{
				JE_OPENGL_EXT(glBufferData,(target,size,data,usage))
			}

			//! Delete Buffer
			JE_OPENGL_INLINE void DeleteBuffers(GLsizei n, const GLuint* ids)
			{
				JE_OPENGL_EXT(glDeleteBuffers,(n,ids))
			}

			//! Map VBO buffer
			JE_OPENGL_INLINE void * MapBuffer(GLenum target, GLenum access)
			{
				JE_OPENGL_EXT_RET(glMapBuffer,(target,access),void *)
				JE_OPENGL_EXT_RET_ELSE(NULL)
			}

			//! Unmap VBO buffer
			JE_OPENGL_INLINE u1 UnmapBuffer(GLenum target)
			{
				JE_OPENGL_EXT_RET(glUnmapBuffer,(target)?true:false,u1) // there intresting thing, so argument is only target, conversion true/false related to return argument
				JE_OPENGL_EXT_RET_ELSE(false)
			}

			//! Draw Range Elements
			//! if function dont support by context, auto use drawelements
			JE_OPENGL_INLINE void DrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid *indices)
			{
				JE_OPENGL_EXT(glDrawRangeElements,(mode,start,end,count,type,indices))
			}

			//! Set Active Texture
			JE_OPENGL_INLINE void SetActiveTexture(GLenum texture)
			{
				JE_OPENGL_EXT(glActiveTexture,(texture))
			}

			//! Set Texture Multisample
			JE_OPENGL_INLINE void SetTextureMultisample(GLenum target,GLsizei samples,GLint internalformat,GLsizei width,GLsizei height,GLboolean fixedsamplelocations)
			{
				JE_OPENGL_EXT(glTexImage2DMultisample,(target,samples,internalformat,width,height,fixedsamplelocations))
			}

			//! Generate Frame Buffers
			JE_OPENGL_INLINE void GenerateFramebuffers(GLsizei n,GLuint * framebuffers)
			{
				JE_OPENGL_EXT(glGenFramebuffers,(n,framebuffers))
			}

			//! Delete Frame Buffers
			JE_OPENGL_INLINE void DeleteFramebuffers(GLsizei n,const GLuint * framebuffers)
			{
				JE_OPENGL_EXT(glDeleteFramebuffers,(n,framebuffers))
			}

			//! Bind Frame Buffer
			JE_OPENGL_INLINE void BindFrameBuffer(GLenum target,GLuint framebuffer)
			{
				JE_OPENGL_EXT(glBindFramebuffer,(target,framebuffer))
			}

			//! Generate Render Buffers
			JE_OPENGL_INLINE void GenerateRenderbuffers(GLsizei n,GLuint * renderbuffers)
			{
				JE_OPENGL_EXT(glGenRenderbuffers,(n,renderbuffers))
			}

			//! Delete Render Buffers
			JE_OPENGL_INLINE void DeleteRenderbuffers(GLsizei n,const GLuint * renderbuffers)
			{
				JE_OPENGL_EXT(glDeleteRenderbuffers,(n,renderbuffers))
			}

			//! Bind Render Buffer
			JE_OPENGL_INLINE void BindRenderBuffer(GLenum target,GLuint renderbuffers)
			{
				JE_OPENGL_EXT(glBindRenderbuffer,(target,renderbuffers))
			}

			//! Set Render Buffer Storage
			JE_OPENGL_INLINE void SetRenderBufferStorage(GLenum target,GLenum internalformat,GLsizei width,GLsizei height)
			{
				JE_OPENGL_EXT(glRenderbufferStorage,(target,internalformat,width,height))
			}

			//! Get Render Buffer Parametr
			JE_OPENGL_INLINE void GetRenderBufferParametr(GLenum target,GLenum pname,GLint *params)
			{
				JE_OPENGL_EXT(glGetRenderbufferParameteriv,(target,pname,params))
			}

			//! Set Frame Buffer Texture 2D
			JE_OPENGL_INLINE void SetFrameBufferTexture2D(GLenum target,GLenum attachment,GLenum textarget,GLuint texture,GLint level)
			{
				JE_OPENGL_EXT(glFramebufferTexture2D,(target,attachment,textarget,texture,level))
			}

			//! Set Frame Buffer Render Buffer
			JE_OPENGL_INLINE void SetFrameBufferRenderBuffer(GLenum target,GLenum attachment,GLenum renderbuffertarget,GLuint renderbuffer)
			{
				JE_OPENGL_EXT(glFramebufferRenderbuffer,(target,attachment,renderbuffertarget,renderbuffer))
			}

			//! Chech Frame Buffer Status
			JE_OPENGL_INLINE GLenum ChechFrameBufferStatus(GLenum target)
			{
				JE_OPENGL_EXT_RET(glCheckFramebufferStatus,(target),GLenum)
				JE_OPENGL_EXT_RET_ELSE(NULL)
			}

			//! Generate Mipmap
			JE_OPENGL_INLINE void GenerateMipmap(GLenum target)
			{
				JE_OPENGL_EXT(glGenerateMipmap,(target))
			}

			//! Draw Buffers
			JE_OPENGL_INLINE void DrawBuffers(GLsizei n,const GLenum * bufs)
			{
				JE_OPENGL_EXT(glDrawBuffers,(n,bufs))
			}

			//! Blit Frame Buffers
			JE_OPENGL_INLINE void BlitFrameBuffers(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
			{
				JE_OPENGL_EXT(glBlitFramebuffer,(srcX0,srcY0,srcX1,srcY1,dstX0,dstY0,dstX1,dstY1,mask,filter))
			}

			//! Set Render Buffer Storage Multisample
			JE_OPENGL_INLINE void SetRenderBufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
			{
				JE_OPENGL_EXT(glRenderbufferStorageMultisample,(target,samples,internalformat,width,height))
			}

			//! Attach Shader
			JE_OPENGL_INLINE void AttachShader(GLuint prog,GLuint shader)
			{
				JE_OPENGL_EXT(glAttachShader,(prog,shader))
			}

			//! Bind Attribute Location
			JE_OPENGL_INLINE void BindAttributeLocation(GLuint prog,GLuint index,const GLchar * name)
			{
				JE_OPENGL_EXT(glBindAttribLocation,(prog,index,name))
			}

			//! Compile Shader
			JE_OPENGL_INLINE void CompileShader(GLuint shader)
			{
				JE_OPENGL_EXT(glCompileShader,(shader))
			}

			//! Create Program
			JE_OPENGL_INLINE GLuint CreateProgram()
			{
				JE_OPENGL_EXT_RET(glCreateProgram,(),GLuint)
				JE_OPENGL_EXT_RET_ELSE(NULL)
			}

			//! Create Shader
			JE_OPENGL_INLINE GLuint CreateShader(GLenum type)
			{
				JE_OPENGL_EXT_RET(glCreateShader,(type),GLuint)
				JE_OPENGL_EXT_RET_ELSE(NULL)
			}

			//! Delete Program
			JE_OPENGL_INLINE void DeleteProgram(GLuint prog)
			{
				JE_OPENGL_EXT(glDeleteProgram,(prog))
			}

			//! Delete Shader
			JE_OPENGL_INLINE void DeleteShader(GLuint shader)
			{
				JE_OPENGL_EXT(glDeleteShader,(shader))
			}

			//! Detach Shader
			JE_OPENGL_INLINE void DetachShader(GLuint prog,GLuint shader)
			{
				JE_OPENGL_EXT(glDetachShader,(prog,shader))
			}

			//! Disable Vertex Attribute Array
			JE_OPENGL_INLINE void DisableVertexAttributeArray(GLuint attribute)
			{
				JE_OPENGL_EXT(glDisableVertexAttribArray,(attribute))
			}

			//! Enable Vertex Attribute Array
			JE_OPENGL_INLINE void EnableVertexAttributeArray(GLuint attribute)
			{
				JE_OPENGL_EXT(glEnableVertexAttribArray,(attribute))
			}

			//! Get Attribute Location
			JE_OPENGL_INLINE GLint GetAttributeLocation(GLuint prog,const GLchar * name)
			{
				JE_OPENGL_EXT_RET(glGetAttribLocation,(prog,name),GLint)
				JE_OPENGL_EXT_RET_ELSE(-1)
			}

			//! Get Program Info State
			JE_OPENGL_INLINE void GetProgramInfoState(GLuint prog,GLenum state,GLint * retstate)
			{
				JE_OPENGL_EXT(glGetProgramiv,(prog,state,retstate))
			}

			//! Get Program Info Log
			JE_OPENGL_INLINE void GetProgramInfoLog(GLuint prog,GLsizei maxlength,GLsizei * length,GLchar * log)
			{
				JE_OPENGL_EXT(glGetProgramInfoLog,(prog,maxlength,length,log))
			}

			//! Get Shader Info State
			JE_OPENGL_INLINE void GetShaderInfoState(GLuint shader,GLenum state,GLint * retstate)
			{
				JE_OPENGL_EXT(glGetShaderiv,(shader,state,retstate))
			}

			//! Get Shader Info Log
			JE_OPENGL_INLINE void GetShaderInfoLog(GLuint shader,GLsizei maxlength,GLsizei * length,GLchar * log)
			{
				JE_OPENGL_EXT(glGetShaderInfoLog,(shader,maxlength,length,log))
			}

			//! Get Uniform Location
			JE_OPENGL_INLINE GLint GetUniformLocation(GLuint prog,const GLchar * name)
			{
				JE_OPENGL_EXT_RET(glGetUniformLocation,(prog,name),GLuint)
				JE_OPENGL_EXT_RET_ELSE(-1)
			}

			//! Link Program
			JE_OPENGL_INLINE void LinkProgram(GLuint prog)
			{
				JE_OPENGL_EXT(glLinkProgram,(prog))
			}

			//! Set Shader Source
			JE_OPENGL_INLINE void SetShaderSource(GLuint shader,GLsizei stringcount,const GLchar ** string,const GLint * length)
			{
				JE_OPENGL_EXT(glShaderSource,(shader,stringcount,string,length))
			}

			//! Use Program
			JE_OPENGL_INLINE void UseProgram(GLuint prog)
			{
				JE_OPENGL_EXT(glUseProgram,(prog))
			}

			//! Set Uniform 2fp
			JE_OPENGL_INLINE void SetUniform2fp(GLint location,GLfloat v0,GLfloat v1)
			{
				JE_OPENGL_EXT(glUniform2f,(location,v0,v1))
			}

			//! Set Uniform 3fp
			JE_OPENGL_INLINE void SetUniform3fp(GLint location,GLfloat v0,GLfloat v1,GLfloat v2)
			{
				JE_OPENGL_EXT(glUniform3f,(location,v0,v1,v2))
			}

			//! Set Uniform 2ip
			JE_OPENGL_INLINE void SetUniform2ip(GLint location,GLint v0,GLint v1)
			{
				JE_OPENGL_EXT(glUniform2i,(location,v0,v1))
			}

			//! Set Uniform 3ip
			JE_OPENGL_INLINE void SetUniform3ip(GLint location,GLint v0,GLint v1,GLint v2)
			{
				JE_OPENGL_EXT(glUniform3i,(location,v0,v1,v2))
			}

			//! Set Uniform 1fv
			JE_OPENGL_INLINE void SetUniform1fv(GLint location,GLsizei size,const GLfloat * data)
			{
				JE_OPENGL_EXT(glUniform1fv,(location,size,data))
			}

			//! Set Uniform 3fv
			JE_OPENGL_INLINE void SetUniform3fv(GLint location,GLsizei size,const GLfloat * data)
			{
				JE_OPENGL_EXT(glUniform3fv,(location,size,data))
			}

			//! Set Uniform 1iv
			JE_OPENGL_INLINE void SetUniform1iv(GLint location,GLsizei size,const GLint * data)
			{
				JE_OPENGL_EXT(glUniform1iv,(location,size,data))
			}

			//! Set Uniform Matrix 3fv
			JE_OPENGL_INLINE void SetUniformMatrix3fv(GLint location,GLsizei size,GLboolean transpose,const GLfloat * data)
			{
				JE_OPENGL_EXT(glUniformMatrix3fv,(location,size,transpose,data))
			}

			//! Set Uniform Matrix 4fv
			JE_OPENGL_INLINE void SetUniformMatrix4fv(GLint location,GLsizei size,GLboolean transpose,const GLfloat * data)
			{
				JE_OPENGL_EXT(glUniformMatrix4fv,(location,size,transpose,data))
			}

			//! Validate Program
			JE_OPENGL_INLINE void ValidateProgram(GLuint prog)
			{
				JE_OPENGL_EXT(glValidateProgram,(prog))
			}

			//! Set Vertex Attribute Pointer
			JE_OPENGL_INLINE void SetVertexAttributePointer(GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const GLvoid * pointer)
			{
				JE_OPENGL_EXT(glVertexAttribPointer,(index,size,type,normalized,stride,pointer))
			}

			//! Bind Fragment Data Location
			JE_OPENGL_INLINE void BindFragmentDataLocation(GLuint program,GLuint color,const GLchar * name)
			{
				JE_OPENGL_EXT(glBindFragDataLocation,(program,color,name))
			}

			// --------------------------- Old Functions ---------------------------
			// we cannot directly include gl.h to OpenGL Render, and cannot call opengl functions directly, so old functions for opengl 1.1 go here
			
			//! Projection Matrix Mode
			void Old_MatrixModeProjection();

			//! Model View Matrix Mode
			void Old_MatrixModeModelView();

			//! Texture Matrix Mode
			void Old_MatrixModeTexture();

			//! Load Matrix Values
			void Old_LoadMatrixValues(f32 * Elem);

			//! Enable Client State Vertex Array
			void Old_EnableClientStateVertexArray();

			//! Enable Client State Texture Coordination Array
			void Old_EnableClientStateTextureCoordinationArray();

			//! Enable Client State Color Array
			void Old_EnableClientStateColorArray();

			//! Disable Client State Vertex Array
			void Old_DisableClientStateVertexArray();

			//! Disable Client State Texture Coordination Array
			void Old_DisableClientStateTextureCoordinationArray();

			//! Disable Client State Color Array
			void Old_DisableClientStateColorArray();

			//! Vertex Pointer
			void Old_SetVertexPointer(s32 Stride,void * Ptr);

			//! Texture Coordination Pointer
			void Old_SetTextureCoordinationPointer(s32 Stride,void * Ptr);

			//! Color Pointer
			void Old_SetColorPointer(u8 Count,u8 Size,s32 Stride,void * Ptr);
		};

	}
}
#endif

#endif
